﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using HslCommunication.Profinet.Siemens;
using HslCommunication;
using System.Drawing.Imaging;
using 货物监控;
using 货物监控.Properties;
using System.Threading;
using System.Runtime.InteropServices.ComTypes;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Diagnostics;
using PdfiumViewer;
using MQTTnet.Client;
using MQTTnet;
using System.Security.Cryptography.X509Certificates;
using Model;
using System.Diagnostics.Eventing.Reader;
using System.Resources;
using System.Net.NetworkInformation;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using DAL;
using System.Windows.Forms.VisualStyles;
using System.Net.Http;

namespace 货物监控
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;

        }
        #region 全局变量
        string plc1_ip = "10.95.24.38";         // PLC1 IP
        //string plc1_ip = "192.168.1.5";         // PLC1 IP
        string plc2_ip = "10.95.24.39";         // PLC2 IP
        StationRecord[] stationRecords = new StationRecord[8];
        Label[] suLabels,huLabels,wrapLabels,printLabels, stackLabels,suUpLabels,huUpLabels,partLabels;
        PictureBox[] ST_PICs;
        int printFlag = 0;                      // 打印机状态
        public string TempPath = "D:/Temp/JPG/";    //打印图片存储路径 
        TcpClient printClient = new TcpClient();// 打印机客户端
        private NetworkStream stream;           // 打印机数据流
        int print_status;                   // 打印机状态
        int waitRaiseTime = 300;                // ST60位置提升机等待时间
        int realTime = 0;                     // ST60位置等待提升机的实时时间
        IniConfig ini = new IniConfig("./config.ini"); // 配置文件
        public SiemensS7Net plc1 = new SiemensS7Net(SiemensPLCS.S1200); // PLC 1
        public SiemensS7Net plc2 = new SiemensS7Net(SiemensPLCS.S1200); // PLC 2
        //网络打印PDF路径
        string PrintPath = "A:\\01_label_Output\\";
        string newPrintPath = "D:\\Temp\\PDF\\";
        string newPrintFile = "";
        SQL_Func sql_func = new SQL_Func();
        string ini_text = "待更新";
        string ini_bool = "0";
        string noChange = "no";
        private static readonly Mutex LogMutex = new Mutex(); // 在类的成员变量中声明互斥锁
        bool track_flag = false;
        int track_intflag = 0;
        public string AGVString = File.ReadAllText("AGV.txt").Trim();
        public static string pushString = File.ReadAllText("SAP.txt").Trim();
        int agv_position;
        // 声明一个全局变量
        Dictionary<string, Dictionary<string, object>> dict_pos;
        // 从文件读取 JSON 字符串
        string json = File.ReadAllText("pos_info.json");
        string speaker_url = "http://192.168.1.28/v1/speech";  // 音响http请求地址
        #endregion


        #region PLC点位
        string st10_request = "DB200.DBX218.0";     // 【读取/写入】【Bool】ST10请求
        string st10_barCode = "DB200.DBB0";         // 【读取】【string】ST10条码
        string st10_haveSuNum = "DB200.DBX210";     // 【写入】【Int】判断SU号的
        string st10_wrap = "DB21.DBX468";     // 【写入】【Int】判断SU号的
        string st10_print = "DB21.DBX470";     // 【写入】【Int】判断SU号的
        string st10_stack = "DB21.DBX472";     // 【写入】【Int】判断SU号的
        string st10_push = "DB21.DBX474";     // 【写入】【Int】判断SU号的
        string st10_ToNum = "DB21.DBB156";      // 写入TO
        string st10_noSuStr = "DB200.DBX52.0";      // 【写入】【string】写入异常字符串
        string st20_request = "DB200.DBX438.0";     // 【读取/写入】【Bool】ST20请求
        string st20_barCode = "DB200.DBB220";       // 【读取】【string】ST20条码
        string st20_wrap = "DB200.DBW430";          // 【写入】【Int】ST20写入是否缠膜，缠膜1，不缠膜2
        string st30_request = "DB200.DBX658.0";     // 【读取/写入】【Bool】ST30请求
        string st30_barCode = "DB200.DBB440";       // 【读取】【string】ST30条码
        string st40_request = "DB200.DBX878.0";     // 【读取/写入】【Bool】ST40请求
        string st40_isExist = "DB200.DBX878.5";     // 【写入】【int】ST40打印文件不存在
        string st40_printFile = "DB200.DBB764.0";  // ST40 【写入】【string】找不到打印文件，将文件名写到PLC
        string st40_barCode = "DB200.DBX660";       // 【读取】【string】ST40读码
        string st40_print = "DB200.DBW870";         // 【写入】【int】ST40打印 1.打印，2.不打印
        string st40_request2 = "DB200.DBX878.2";    // 【读取/写入】【Bool】ST40 请求2
        string st40_reprint = "DB200.DBX878.3";     // ST40 重新打印
        string st40_printReady = "DB200.DBX878.4";  // ST40 【写入】【bool】打印就绪，就是打印完成，打印完成写1，打印就绪写2
        string st40_printing = "DB200.DBX878.7";    // ST40 【写入】【bool】
        string st40_huCode = "DB200.DBB712";        // ST40 【读取】【string】贴完标读到的内容
        string st50_request = "DB200.DBX1098.0";    // ST50 【读取/写入】【Bool】请求
        string st50_barCode = "DB200.DBB880";       // ST50 【读取】【string】条码信息
        string st50_huCode = "DB200.DBB932";        // ST50 【读取】【string】贴完标读到的内容
        string st60_request = "DB200.DBX1318.0";    // ST60 【读取/写入】【Bool】请求
        string st60_barCodeDown = "DB200.DBB1100";      // ST60 【读取】【string】读码
        string st60_barCodeUP = "DB200.DBB1204";      // ST60 【读取】【string】读码
        string st60_huCodeUp = "DB200.DBB1256";      // ST60 【读取】【string】读码
        string st60_huCodeDown = "DB200.DBB1152";      // ST60 【读取】【string】读码
        string st60_isStock = "DB200.DBX1318.4";    // ST60 【读取】【Bool】判断堆叠机上面是否有货  
        string st60_Stack = "DB200.DBW1310";        // ST60 【写入】【int】堆叠机上有货，堆叠1，不堆叠2
        string st60_request2 = "DB200.DBX1318.2";   // ST60 请求2  True堆叠完成，False堆叠未完成
        string st70_request = "DB200.DBX1538.0";    // ST70 请求
        string st70_Push = "DB200.DBW1530";         // ST70 侧推气缸
        string st70_leave = "DB200.DBX1538.2";   // 【读取】ST70 请求拉走
        string st70_leaved = "DB200.DBX1760.2";       // 【读取】ST80 判断是否拉走
        string st70_barCodeDown = "DB200.DBX1320";       // 【读取】ST80 判断是否拉走
        string st70_barCodeUp = "DB200.DBX1424";       // 【读取】ST80 判断是否拉走
        string st70_huCodeDown = "DB200.DBX1372";       // 【读取】ST80 判断是否拉走
        string st70_huCodeup = "DB200.DBX1476";       // 【读取】ST80 判断是否拉走



        // DB21.DBB0.0  ST10数据
        // DB21.DBB0.0  ST10数据
        // DB21.DBB0.0  ST10数据
        // DB21.DBB0.0  ST10数据
        // DB21.DBB0.0  ST10数据
        // DB21.DBB0.0  ST10数据
        // DB21.DBB0.0  ST10数据
        // W整数，B字符串，X Bool值
        #endregion
        
        
        
        private void Form1_Load(object sender, EventArgs e)
        {
            if (!HslCommunication.Authorization.SetAuthorizationCode("f44b3795-d88e-4d48-b7c9-d38e3c48441e"))
            {
                MessageBox.Show("授权失败！当前程序只能使用8小时！");
            }


            suLabels = new Label[] { suLabelDown1, suLabelDown2, suLabelDown3, suLabelDown4, suLabelDown5, suLabelDown6, suLabelDown7, suLabelDown8 };
            huLabels = new Label[] { huLabelDown1, huLabelDown2, huLabelDown3, huLabelDown4, huLabelDown5, huLabelDown6, huLabelDown7, huLabelDown8 };
            wrapLabels = new Label[] { wrapLabel1, wrapLabel2, wrapLabel3, wrapLabel4, wrapLabel5, wrapLabel6, wrapLabel7, wrapLabel8 };
            
            printLabels = new Label[] { printLabel1, printLabel2, printLabel3, printLabel4, printLabel5, printLabel6, printLabel7, printLabel8 };
            stackLabels = new Label[] { stackLabel1, stackLabel2, stackLabel3, stackLabel4, stackLabel5, stackLabel6, stackLabel7, stackLabel8, };
            suUpLabels = new Label[] { suLabelUp1,suLabelUp2,suLabelUp3,suLabelUp4,suLabelUp5, suLabelUp6, suLabelUp7, suLabelUp8 };
            huUpLabels= new Label[] { huLabelUp1, huLabelUp2, huLabelUp3, huLabelUp4, huLabelUp5, huLabelUp6, huLabelUp7, huLabelUp8 };
            ST_PICs = new PictureBox[] { ST10_Pic, ST20_Pic, ST30_Pic, ST40_Pic, ST50_Pic, ST60_Pic, ST70_Pic, ST80_Pic };
            partLabels = new Label[] { partLabel1, partLabel2, partLabel3, partLabel4, partLabel5, partLabel6, partLabel7, partLabel8 };
            agv_position = Convert.ToInt32(ini.ReadKey("agv_position"));
            Task.Run(() => ConnectPrinter());   //打印机连接
            Task.Run(() => ConnPLC(plc1_ip));   // 连接PLC
            timer1.Start();

            // 连接AGV
            Task.Run(async () =>
            {
                TlsClientAGV("AmazonRootCA1.pem").Wait();
            });
            // 连接MQTT
            Task.Run(async () =>
            {
                TlsClient("whas007.wh.cn.int.Vitesco.com", 1883).Wait();
            });


            // 反序列化为字典
            dict_pos = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, object>>>(json);
            status_timer.Start();
            st_timer.Start();
            data_timer.Start();

        }


        






        // 关闭窗口提醒
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            DialogResult result = MessageBox.Show("您确定关闭当前界面吗?", "温馨提示", MessageBoxButtons.YesNo);
            if (result == DialogResult.No)
            {
                e.Cancel = true;
            }
            else
            {
                if (Application.OpenForms.Count == 0)
                    Application.Exit();
            }
        }

        #region 计时器

        // PLC心跳，打印机心跳
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (printFlag > 0)
            {
                PrintHreat();  // 连接以后发送打印机心跳
            }
            plc1Heart();
            agvLabel.Text = $"AGV送达点位：{agv_position}号位";
        }



        // 状态计时器
        private void status_timer_Tick(object sender, EventArgs e)
        {
            List<int> numbers = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7 };
            
            foreach (var key in dict_pos.Keys)
            {
                int serial = Convert.ToInt32(dict_pos[key]["position"]);
                suLabels[serial].Text = "SU:" + key.ToString();
                huLabels[serial].Text = "HU:"+ dict_pos[key]["hu"].ToString();
                partLabels[serial].Text = dict_pos[key]["part_name"].ToString();
                suUpLabels[serial].Text = "SU上:" + dict_pos[key]["su_up"].ToString();
                huUpLabels[serial].Text = "HU上:" + dict_pos[key]["hu_up"].ToString();
                ST_PICs[serial].Image = Resources.green_circle;
                numbers.Remove(serial);
            }
            foreach (var number in numbers)
            {
                suLabels[number].Text = "";
                suLabels[number].Text = "";
                huLabels[number].Text = "";
                wrapLabels[number].Text = "";
                printLabels[number].Text = "";
                stackLabels[number].Text = "";
                partLabels[number].Text = "";
                suUpLabels[number].Text = "";
                huUpLabels[number].Text = "";
                ST_PICs[number].Image = Resources.gray_circle;
            }
        }
        // ST流程的计时器
        private void st_timer_Tick(object sender, EventArgs e)
        {
            // ST10请求 
            if (ReadBool(st10_request))
            {
                string barCode_str = ReadNumberString(st10_barCode); // 读取条码
                barCode_str = barCode_str.Replace(" ", "");
                
                BarCode bc = splicBar(barCode_str); // 解析条码
                XY_part part_data = sql_func.SelectPNumber(bc.零件号);//查询零件号是否需要缠膜
                if (part_data == null)
                {
                    ShowMsg($"未查询到零件号{bc.零件号}");
                    WriteInt(st10_haveSuNum, 2); // 没有SU号
                    writeString(st10_noSuStr, "No PartNum");
                }
                else
                {
                    ShowMsg($"ST10读取条码内容为：{barCode_str}");
                    int Count = sql_func.getSU(bc.SU号);
                    if (Count == 0)
                    {
                        WriteInt(st10_haveSuNum, 2); // 没有SU号
                        ShowMsg("没有查到相关项目号");// 
                        writeString(st10_noSuStr, "No SuCode");
                        ShowMsg("没有查到相关项目号,重新开启St10函数");// 
                    }
                    else
                    {
                        WriteInt(st10_haveSuNum, 1); // 有SU号，继续
                        bool st10_status = sql_func.Update10(bc.SU号, XY_task.WorkState.完成); // 更新ST10数据库
                        ShowMsg("ST10 完成");
                        WriteInt(st10_wrap,Convert.ToInt16(part_data.PWrapping));
                        WriteInt(st10_print,Convert.ToInt16(part_data.PPaying));
                        WriteInt(st10_stack,Convert.ToInt16(part_data.PStacking));
                        WriteInt(st10_push,Convert.ToInt16(part_data.PDirection));
                        XY_taskdetail Td = sql_func.SelectStorage_unit_number(bc.SU号);
                        writeString(st10_ToNum,Td.orderID);
                        //ShowMsg($"st10_wrap{ReadInt(st10_wrap)},st10_print:{ReadInt(st10_print)},st10_stack：{ReadInt(st10_stack)}，st10_push：{ReadInt(st10_push)}");


                        ShowMsg($"更新缠膜：{part_data.PWrapping},贴标：{part_data.PPaying},堆叠：{part_data.PStacking},侧推{part_data.PDirection}");
                        if (dict_pos.ContainsKey(bc.SU号) && bc.SU号 != null)
                        {
                            dict_pos[bc.SU号]["part_name"] = bc.零件号;
                            dict_pos[bc.SU号]["hu"] = "";
                            dict_pos[bc.SU号]["su_up"] = "";
                            dict_pos[bc.SU号]["hu_up"] = "";
                            dict_pos[bc.SU号]["position"] = 0;
                        }
                        else
                        {
                            dict_pos[bc.SU号] = new Dictionary<string, object>
                            {
                                { "part_name", bc.零件号 },
                                { "hu", "" },
                                { "su_up", "" },
                                { "hu_up", "" },
                                { "position", 0 }
                            };
                        }
                    }
                   
                }
                WriteFalse(st10_request); // 写入False
                if (ReadBool(st10_request))
                {
                    WriteFalse(st10_request);  // 再写一边
                    ShowMsg($"写入失败，重写st10_request:{st10_request}");
                }

            }
            // ST40请求
            if (ReadBool(st40_request))
            {
                string barCode = ReadNumberString(st40_barCode); // 读码
                BarCode bc = splicBar(barCode); // 读码
                if (dict_pos.ContainsKey(bc.SU号))
                {
                    dict_pos[bc.SU号]["part_name"] = bc.零件号;
                    dict_pos[bc.SU号]["hu"] = "";
                    dict_pos[bc.SU号]["su_up"] = "";
                    dict_pos[bc.SU号]["hu_up"] = "";
                    dict_pos[bc.SU号]["position"] = 4;
                }
                else
                {
                    dict_pos[bc.SU号] = new Dictionary<string, object>
                    {
                        { "part_name", bc.零件号 },
                        { "hu", "" },
                        { "su_up", "" },
                        { "hu_up", "" },
                        { "position", 4 }
                    };
                }
                dict_pos[bc.SU号]["position"] = 3;
                XY_taskdetail Td = sql_func.SelectStorage_unit_number(bc.SU号);
                bool bl = sql_func.Update40(bc.SU号, XY_task.WorkState.进入);// 更新数据库
                string print_file = Td.dropdown_station_storage_bin.TrimStart('0') + "_" + Td.item;
                string PDFPath = PrintPath + print_file + ".pdf"; // pdf路径
                string newPDFPath = newPrintPath + print_file + ".pdf";
                ShowMsg($"打印文件为：{print_file}.pdf");

                printFileLabel.Text = $"打印文件：{print_file}.pdf"; // 将打印的文件名称更新在界面上
                if (!File.Exists(PDFPath))
                {
                    WriteBool(st40_isExist, true); // 文件存在
                }
                else
                {
                    move_file(PDFPath, newPDFPath); // 将旧文件移动到新文件夹
                    newPrintFile = newPDFPath; // 赋值给全局变量
                    // 更新st40进度为
                    string PngPath = getPath(Td.PrintTask);// 获取png路径
                    PdfToImage(newPDFPath, PngPath);// 转换图片并且保存到本地
                    NetForm.PrintImage(PngPath); //
                    WriteBool(st40_printing, true);
                    print_timer.Start();
                }
                WriteFalse(st40_request);
            }
             
            //if (ReadBool(st40_request2))
            if(false)
            {
                string barCode = ReadNumberString(st40_barCode); // 读码
                BarCode bc = splicBar(barCode); // 读码
                string hu_num = ReadNumberString("DB200.DBB712").Trim().Replace("\0", "");
                if (dict_pos.ContainsKey(bc.SU号))
                {
                    dict_pos[bc.SU号]["part_name"] = bc.零件号;
                    dict_pos[bc.SU号]["hu"] = hu_num;
                    dict_pos[bc.SU号]["su_up"] = "";
                    dict_pos[bc.SU号]["hu_up"] = "";
                    dict_pos[bc.SU号]["position"] = 3;
                }
                else
                {
                    dict_pos[bc.SU号] = new Dictionary<string, object>
                    {
                        { "part_name", bc.零件号 },
                        { "hu", hu_num },
                        { "su_up", "" },
                        { "hu_up", "" },
                        { "position", 3 }
                    };
                }
                //保存HU
                bool b = sql_func.UpdateHU(bc.SU号, hu_num);
                XY_taskdetail Td = sql_func.SelectStorage_unit_number(bc.SU号);
                sql_func.Update42(bc.SU号, hu_num, XY_task.WorkState.完成, Td.PrintTask);
                // 更新数据库完成
                dict_pos[bc.SU号]["hu"] = hu_num;
                WriteFalse(st40_request2);
                if (ReadBool(st40_request2))
                {
                    WriteFalse(st40_request2);  // 再写一边
                    ShowMsg($"写入失败，重写st40_request2:{st40_request2}");
                }
            }
            // st70请求
            if (ReadBool(st70_leave))
            {
                string barCodeDown = ReadNumberString(st70_barCodeDown); // 读码

                if (barCodeDown.Substring(0, 4) != "    ")
                {
                    BarCode bcDown = splicBar(barCodeDown);
                    if (!dict_pos.ContainsKey(bcDown.SU号))
                    {
                        dict_pos[bcDown.SU号] = new Dictionary<string, object>
                        {
                            { "part_name", "" },
                            { "hu", "" },
                            { "su_up", "" },
                            { "hu_up", "" },
                            { "position", 6 }
                        };
                    }
                    dict_pos[bcDown.SU号]["position"] = 6;
                    dict_pos[bcDown.SU号]["part_name"] = bcDown.零件号;
                    sql_func.Update70(bcDown.SU号, XY_task.WorkState.完成);// 更新下托信息
                    ShowMsg("ST70更新下托信息");

                    string hu_num_down = ReadNumberString(st70_huCodeup).Replace("\0", "");
                    hu_num_down = hu_num_down.StartsWith("    ") ? "" : hu_num_down;
                    dict_pos[bcDown.SU号]["hu"] = hu_num_down;
                    XY_taskdetail task_data = sql_func.SelectStorage_unit_number(bcDown.SU号);
                    // 更新AGV点位信息
                    update_agv_data(agv_position, task_data.orderID, task_data.dropdown_station_storage_bin, bcDown.零件号, hu_num_down, bcDown.SU号, 1); // 1下托，0上托
                    string barCodeUp = ReadNumberString(st70_barCodeUp); // 读码
                    if (barCodeUp.Substring(0, 4) != "    ")
                    {
                        BarCode bcUp = splicBar(barCodeUp);
                        dict_pos[bcDown.SU号]["su_up"] = bcUp.SU号; // 上托信息
                        sql_func.Update70(bcUp.SU号, XY_task.WorkState.完成);// 更新上托信息
                        ShowMsg("ST70更新上托信息");
                        string hu_num_up = ReadNumberString(st70_huCodeup).Replace("\0", "");
                        hu_num_up = hu_num_up.StartsWith("    ") ? "" : hu_num_up;
                        dict_pos[bcDown.SU号][bcUp.SU号] = hu_num_up;
                        dict_pos.Remove(bcUp.SU号);
                        // 更新AGV点位信息
                        update_agv_data(agv_position,task_data.orderID, task_data.dropdown_station_storage_bin, bcDown.零件号, hu_num_up, bcUp.SU号, 0);// 1下托，0上托
                    }
                    else
                    {
                        update_agv_data(agv_position, "","", "", "", "", 0);
                    }
                    MQTTPush(bcDown.SU号); // 回传SAP
                    callAgv(agv_position,"2"); // 呼叫AGV
                   
                }
                WriteFalse(st70_leave);
            }

            if (ReadBool(st70_leaved))
            {
                string barCodeDown = ReadNumberString(st70_barCodeDown); // 读码
                if (barCodeDown.Substring(0, 4) != "    ")
                {
                    BarCode bcDown = splicBar(barCodeDown);
                    sql_func.Update80(bcDown.SU号);
                    // 更新AGV点位信息
                    MQTTPush(bcDown.SU号); // 回传SAP
                    string barCodeUp = ReadNumberString(st70_barCodeUp); // 读码
                    if (barCodeUp.Substring(0, 4) != "    ")
                    {
                        BarCode bcUp = splicBar(barCodeUp);
                        sql_func.Update80(bcUp.SU号);
                    }
                    dict_pos.Remove(bcDown.SU号);
                }
                audio_play(agv_position);
                agv_position += 1;
                if (agv_position == 4)
                {
                    agv_position = 1;
                }
                WriteFalse(st70_leaved);
            }
        }
        // 打印的计时器
        private void print_timer_Tick(object sender, EventArgs e)
        {
            if (print_status == 4)
            {
                ShowMsg("正在打印");
                WriteBool(st40_printing, true);
            }
            if(print_status == 0)
            {
                ShowMsg("打印完成");
                WriteBool(st40_printReady, true);
                WriteBool(st40_printing, false);
                print_timer.Stop();
            }
        }
        // 数据更新
        private void data_timer_Tick(object sender, EventArgs e)
        {
            // 更新ST20数据
            try
            {
                string barcode2 = ReadNumberString(st20_barCode);
                if (barcode2.Substring(0, 4) != "    ")
                {
                    BarCode bc2 = splicBar(barcode2);
                    if (!dict_pos.ContainsKey(bc2.SU号))
                    {
                        dict_pos[bc2.SU号] = new Dictionary<string, object>
                        {
                            { "part_name", "" },
                            { "hu", "" },
                            { "su_up", "" },
                            { "hu_up", "" },
                            { "position", 1 }
                        };
                    }
                    dict_pos[bc2.SU号]["part_name"] = bc2.零件号;
                    dict_pos[bc2.SU号]["position"] = 1;
                }
            }
            catch(Exception ex)
            {
                ShowMsg($"ST20:{ex.Message}");
            }
            try
            {
                // 更新ST30数据
                string barcode3 = ReadNumberString(st30_barCode);
                if (barcode3.Substring(0, 4) != "    ") // 判断是否为空
                {
                    BarCode bc3 = splicBar(barcode3);
                    if (!dict_pos.ContainsKey(bc3.SU号))
                    {
                        dict_pos[bc3.SU号] = new Dictionary<string, object>
                        {
                            { "part_name", "" },
                            { "hu", "" },
                            { "su_up", "" },
                            { "hu_up", "" },
                            { "position", 2 }
                        };

                    }
                    if (Convert.ToInt32(dict_pos[bc3.SU号]["position"]) != 2)
                    {
                        dict_pos[bc3.SU号]["part_name"] = bc3.零件号;
                        dict_pos[bc3.SU号]["position"] = 2;
                    }
                }
            }
            catch (Exception ex)
            {
                ShowMsg($"ST30:{ex.Message}");
            }

            try
            {
                // 更新ST50数据
                string barcode5 = ReadNumberString(st50_barCode);
                if (barcode5.Substring(0, 4) != "    ")
                {
                    BarCode bc5 = splicBar(barcode5);
                    if (!dict_pos.ContainsKey(bc5.SU号))
                    {
                        dict_pos[bc5.SU号] = new Dictionary<string, object>
                        {
                            { "part_name", "" },
                            { "hu", "" },
                            { "su_up", "" },
                            { "hu_up", "" },
                            { "position", 4 }
                        };
                    }
                    dict_pos[bc5.SU号]["part_name"] = bc5.零件号;
                    dict_pos[bc5.SU号]["position"] = 4;
                    string hu5 = ReadNumberString(st50_huCode).Replace("\0", "");
                    hu5 = hu5.StartsWith("    ") ? "" : hu5;
                    if (dict_pos[bc5.SU号]["hu"].ToString() != hu5)
                    {
                        dict_pos[bc5.SU号]["hu"] = hu5;
                    }
                }
            }
            catch (Exception ex)
            {
                ShowMsg($"ST50:{ex.Message}");
            }


            try
            {
                string barcode_down6 = ReadNumberString(st60_barCodeDown);
                if (barcode_down6.Substring(0, 4) != "    ")
                {
                    BarCode bc_down6 = splicBar(barcode_down6);
                    if (!dict_pos.ContainsKey(bc_down6.SU号))
                    {
                        dict_pos[bc_down6.SU号] = new Dictionary<string, object>
                        {
                            { "part_name", "" },
                            { "hu", "" },
                            { "su_up", "" },
                            { "hu_up", "" },
                            { "position", 5 }
                        };
                    }
                    dict_pos[bc_down6.SU号]["part_name"] = bc_down6.零件号;
                    dict_pos[bc_down6.SU号]["position"] = 5;
                    
                    string hu_down6 = ReadNumberString(st60_huCodeDown).Replace("\0", "");
                    hu_down6 = hu_down6.StartsWith("    ") ? "" : hu_down6;
                    if (dict_pos[bc_down6.SU号]["hu"].ToString() != hu_down6)
                    {
                        dict_pos[bc_down6.SU号]["hu"] = hu_down6;
                    }
                    string barcode_up6 = ReadNumberString(st60_barCodeUP);
                    if (barcode_up6.Substring(0, 4) != "    ")
                    {
                        BarCode bc_up6 = splicBar(barcode_up6);
                        dict_pos[bc_down6.SU号]["su_up"] = bc_down6.SU号;
                        string hu_up6 = ReadNumberString(st60_huCodeUp).Replace("\0", "");
                        hu_up6 = hu_up6.StartsWith("    ") ? "" : hu_up6;
                        if (dict_pos[bc_down6.SU号]["hu_up"].ToString() != hu_up6)
                        {
                            dict_pos[bc_down6.SU号]["hu"] = hu_up6;
                        }
                    }
                }
            }

            catch (Exception ex)
            {
                ShowMsg($"ST60:{ex.Message}");
            }

        }


        // 日志打印
        private void ShowMsg(string str)
        {
            try
            {
                txtLog.AppendText(DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss] ") + str + "\r\n");
                LogMutex.WaitOne(); // 获取互斥锁
                string fileName = DateTime.Now.ToString("yyyy_MM_dd_") + "log.txt";
                using (StreamWriter writer = File.AppendText(fileName))
                {
                    writer.WriteLine($"{DateTime.Now.ToString("[yyyy-MM-dd HH:mm:ss]")} - {str}");
                }
            }
            finally
            {
                LogMutex.ReleaseMutex(); // 释放互斥锁
            }
        }
        // 解析BarCode
        BarCode splicBar(string Bar)
        {
            Bar = Bar.Replace(",", "");

            string[] arr = Bar.Split('|');

            BarCode bc = new BarCode();
            if (arr.Length == 5)
            {
                bc.零件号 = arr[0].Trim();
                bc.工厂代码 = arr[1];
                bc.数量 = Convert.ToInt32(arr[2]);
                bc.SU号 = arr[3];
                bc.入库日期 = arr[4];
            }

            return bc;
        }
        #endregion

        #region 按钮



        private void ST_Pic_Click(object sender, EventArgs e)
        {
            PictureBox st_pic = sender as PictureBox;
            int index = Array.IndexOf(ST_PICs, st_pic);


        }

        private void waitTimeUpDown2_ValueChanged(object sender, EventArgs e)
        {
            // 获取 NumericUpDown 的整数值
            waitRaiseTime = (int)waitTimeUpDown.Value;
        }

        private void button5_Click(object sender, EventArgs e)
        {
            realTime -= 10;
        }

        private void button4_Click(object sender, EventArgs e)
        {
            realTime += 10;
        }

        #endregion

        #region PLC控制函数
        public bool ConnPLC(string ip)
        {
            // 连接  
            plc1.Rack = byte.Parse("0");
            plc1.Slot = byte.Parse("1");
            plc1.IpAddress = ip;
            plc1.Port = 102;
            try
            {
                OperateResult connect = plc1.ConnectServer();
                if (connect.IsSuccess)
                {
                    ShowMsg("PLC连接成功...");
                    PLC_PIC.Image = Resources.color_plc;
                    return true;
                }
                else
                {
                    ShowMsg("PLC掉线...");
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        // PLC写整数
        public void WriteInt(string key, short num)
        {
            plc1.Write(key, num);

            Task.Delay(200).Wait();

        }

        public short ReadInt(string key)
        {
            short num = Convert.ToInt16(plc1.ReadInt16(key));
            Task.Delay(200).Wait();
            return num;

        }


        // PLC写False
        public void WriteFalse(string key)
        {

            plc1.Write(key, false);

            Task.Delay(200).Wait();

        }


        // PLC写Bool
        public bool WriteBool(string key, bool r)
        {
            OperateResult Result = plc1.Write(key, r);
            return Result.IsSuccess;
        }
        // 读取字符串
        public string ReadNumberString(string key, ushort length = 50)
        {
            OperateResult<string> result = plc1.ReadString(key, length);

            string str = result.Content.Substring(2, 48);

            return str;
        }

        // 写入字符串
        void writeString(string key,string text)
        {
            plc1.Write(key, text);
        }

        // PLC心跳
        public bool plc1Heart()
        {

            bool IsRead = ReadBool("DB200.DBX1540.0");

            bool br = WriteBool("DB200.DBX1540.0", !IsRead);

            return br;
        }

        public bool ReadBool(string key)
        {
            OperateResult<bool> result = plc1.ReadBool(key);

            bool br = result.Content;

            return br;
        }

        #endregion
        #region AGV相关
        // 启功MQTT
        void mqtt_start()
        {

            // MQTT小车
            Task.Run(async () =>
            {
                TlsClientAGV("AmazonRootCA1.pem").Wait();
            });
            
            // MQTT消息
            Task.Run(async () =>
            {
                TlsClient("whas007.wh.cn.int.Vitesco.com", 1883).Wait();
            });
        }
        // AGV小车发送
        public static IMqttClient AGVClient;
        // AGV回传
        public static IMqttClient mqttClient;
        // AGV连接
        public async Task TlsClientAGV(string caFile)
        {
            var mqttFactory = new MqttFactory();

            X509Certificate2 cacert = new X509Certificate2(File.ReadAllBytes(caFile));

            AGVClient = mqttFactory.CreateMqttClient();

            var mqttClientOptions = new MqttClientOptionsBuilder().WithTcpServer("hfms-mosquitto-whu.aws2144.vitesco.io", 8883)
                .WithCredentials("2933", "Hik@12342933")
                .WithTls(
                    new MqttClientOptionsBuilderTlsParameters()
                    {
                        UseTls = true,
                        SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
                        CertificateValidationHandler = (certContext) =>
                        {
                            try
                            {
                                // 创建证书链
                                X509Chain chain = new X509Chain
                                {
                                    ChainPolicy =
                                        {
                                            RevocationMode = X509RevocationMode.NoCheck,
                                            RevocationFlag = X509RevocationFlag.ExcludeRoot,
                                            VerificationFlags = X509VerificationFlags.NoFlag,
                                            VerificationTime = DateTime.Now
                                        }
                                };

                                // 将自定义 CA 证书添加到额外存储中
                                chain.ChainPolicy.ExtraStore.Add(cacert);

                                // 将收到的证书转换为 X509Certificate2 类型
                                var x5092 = new X509Certificate2(certContext.Certificate);

                                // 验证证书链
                                bool isValid = chain.Build(x5092);

                                // 如果验证失败，打印详细信息
                                if (!isValid)
                                {
                                    foreach (var status in chain.ChainStatus)
                                    {
                                        Console.WriteLine($"证书链错误: {status.StatusInformation}");
                                    }
                                }

                                return isValid;
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine($"证书验证异常: {ex.Message}");
                                return false;
                            }
                        }

                    })
                .Build();

            AGVClient.ApplicationMessageReceivedAsync += e =>
            {
                return Task.CompletedTask;
            };

            using (var timeout = new CancellationTokenSource(5000))
            {
                await AGVClient.ConnectAsync(mqttClientOptions, timeout.Token);

                Console.WriteLine("The MQTT client is connected.");
            }

            var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
           .WithTopicFilter(
               f =>
               {
                   f.WithTopic("naise/in/orderManager/create");
               })
           .Build();

            await AGVClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);

            ShowMsg("AGV小车连接成功");

        }
        // 给AGV发送消息
        public void SendAGV(string msg)
        {
            string topic = "naise/in/orderManager/create";
            MqttApplicationMessageBuilder mamb = new MqttApplicationMessageBuilder()
                  .WithTopic(topic)
                  .WithPayload(msg).WithRetainFlag(false);
            AGVClient.PublishAsync(mamb.Build());;
        }
        // 使用 MQTT 协议创建一个客户端，连接到指定的服务器，并订阅主题。
        public async Task TlsClient(string ip, int post)
        {
            var mqttFactory = new MqttFactory();// 创建一个 MQTT 工厂实例
            mqttClient = mqttFactory.CreateMqttClient();// 创建一个 MQTT 客户端实例
            // 配置 MQTT 客户端连接选项，设置目标服务器地址和端口号
            var mqttClientOptions = new MqttClientOptionsBuilder()
                .WithTcpServer(ip, post) // 设置 TCP 服务器的 IP 和端口
                .Build();
            // 设置 MQTT 客户端消息接收事件的处理逻辑
            mqttClient.ApplicationMessageReceivedAsync += e =>
            {
                // 获取主题和消息内容
                string topic = e.ApplicationMessage.Topic; // 消息的主题
                string payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload); // 消息的内容

                //// 在控制台打印接收到的消息
                //ShowMsg($"Received message: Topic={topic}, Payload={payload}");
                //// 调用日志方法显示消息内容
                //ShowMsg($"MQTT接收到消息: Topic={topic}, Payload={payload}");
                // 当前仅完成任务，无具体处理逻辑
                return Task.CompletedTask;
            };
            // 使用超时机制尝试连接到 MQTT 服务器
            using (var timeout = new CancellationTokenSource(5000)) // 设置超时时间为 5000 毫秒
            {
                await mqttClient.ConnectAsync(mqttClientOptions, timeout.Token); // 异步连接到服务器
                Console.WriteLine("The MQTT client is connected."); // 打印连接成功信息
            }
            // 配置订阅选项并订阅主题
            var mqttSubscribeOptions = mqttFactory.CreateSubscribeOptionsBuilder()
                .WithTopicFilter( // 设置订阅的主题
                    f =>
                    {
                        f.WithTopic("fromAgv"); // 订阅主题为 "fromAgv"
                    })
                .Build();
            // 异步订阅主题
            await mqttClient.SubscribeAsync(mqttSubscribeOptions, CancellationToken.None);

            // 显示连接成功消息
            ShowMsg("MQTT连接成功");
        }
        /// <summary>
        /// 发送 MQTT 消息
        /// </summary>
        /// <param name="msg">要发送的消息内容</param>
        public void SendMqtt(string msg)
        {
            // 定义 MQTT 消息的主题
            string topic = "fromAgv";

            // 创建 MQTT 消息
            var message = new MqttApplicationMessageBuilder()
                .WithTopic(topic)               // 设置主题
                .WithPayload(Encoding.UTF8.GetBytes(msg)) // 设置消息内容
                .WithRetainFlag(false)         // 消息不保留（Retain Flag 为 false）
                .Build();

            // 发布消息到 MQTT Broker
            mqttClient.PublishAsync(message).Wait();

            // 日志记录
            //ShowMsg("MQTT发布:" + msg);
        }



        // 呼叫AGV
        public void callAgv(int Site, string Na)
        {

            string json = "";
            try
            {
                if (Na.Equals("1"))
                {

                    Na = "2";
                }
                else
                {

                    Na = "1";
                }

                json = AGVString.Replace("{0}", Site.ToString()).Replace("{1}", Na);

                SendAGV(json);
                ShowMsg("发送给AGV:" + json);
                ShowMsg("AGV呼叫完成");

            }
            catch (Exception e)
            {
                ShowMsg("呼叫AGV:" + e.Message);
                Task.Run(async () =>
                {
                    TlsClientAGV("AmazonRootCA1.pem").Wait();
                    callAgv(Site, Na);
                });
            }

        }
        /// <summary>
        /// MQTT回写
        /// </summary>
        /// <param name="SU"></param>
        public void MQTTPush(string SU)
        {
            string json = "";
            try
            {
                PushLine sap = SQL_Func.getSAP70(SU);
                if (sap != null)
                {
                    if (sap.MSite >= 70)
                    {
                        string dt = DateTime.Now.ToString("yyyy-MM-dd HH:MM:ss fff");

                        json = pushString.Replace("{0}", sap.headerId).Replace("{1}", dt).Replace("{2}", sap.orderID);
                        SendMqtt(json);
                        SQL_Func.UpdateSAP70(SU);
                        ShowMsg("回传MQTT信息");
                    }
                }
            }
            catch (Exception e)
            {

                ShowMsg("MQTT回写:" + e.Message);
                ShowMsg("MQTT" + json);
            }
        }
        #endregion
        #region 打印机相关
        // 打印机心跳
        public void PrintHreat()
        {
            string key = "#OM>GP101\r\n";
            SendMsg(printClient, key);
        }

        // 连接打印机，并且进行监视
        private async Task ConnectPrinter()
        {
            string serverAddress = "10.95.16.62";
            int port = 9200;
            try
            {
                await printClient.ConnectAsync(serverAddress, port);
                print_PIC.Image = Resources.printer1;
                ShowMsg($"打印机连接成功");
                printFlag = 1;
                using (NetworkStream stream = printClient.GetStream())
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
                    {
                        // 将接收到的数据转换成字符串并显示
                        string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                        print_status = GetPrinterStatus(receivedData);
                        
                        if (print_status == 0)  // 就绪
                        {
                            print_PIC.Image = Resources.printer1;
                        }
                        else if (print_status == 4) // 正在打印
                        {
                            print_PIC.Image = Resources.printer2;
                        }
                        else if(print_status == 12) // 异常
                        {
                            print_PIC.Image = Resources.printer_error;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ShowMsg($"Error with {serverAddress}:{port}: {ex.Message}");
            }
        }
        int print_num = 20;
        // 日志打印函数
        private async void SendMsg(TcpClient sock, string str)
        {
            var buffer = Encoding.UTF8.GetBytes(str);
            try
            {
                NetworkStream stream = sock.GetStream(); // 每次获取专属的 NetworkStream
                await stream.WriteAsync(buffer, 0, buffer.Length);
                Console.WriteLine($"Message sent: {str}");
            }
            catch (Exception ex)
            {
                ShowMsg($"打印机重连中");
                print_PIC.Image = Resources.no_printer;
                printClient = new TcpClient();
                if (print_num == 20)
                {
                    Task.Run(() => ConnectPrinter());   //打印机连接
                    print_num = 0;
                }
                print_num += 1;
            }
        }

        // 解析打印机返回的状态数据
        public static int GetPrinterStatus(string input)
        {
            try
            {
                // 提取 JSON 格式部分
                int startIndex = input.IndexOf("{");
                int endIndex = input.LastIndexOf("}");
                if (startIndex >= 0 && endIndex > startIndex)
                {
                    string jsonPart = input.Substring(startIndex, endIndex - startIndex + 1);

                    // 使用 Newtonsoft.Json 解析 JSON
                    JObject jsonObject = JObject.Parse(jsonPart);
                    if (jsonObject["printerStatus"] != null)
                    {
                        return jsonObject["printerStatus"].Value<int>();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("解析失败: " + ex.Message);
            }

            // 默认返回值（若未成功解析）
            return -1;
        }
        #endregion
        #region PDF处理
        // 生成PDF图片
        public string getPath(string file_name)
        {

            string PngPath = TempPath + DateTime.Now.ToString("yyyy-MM-dd") + @"/";


            if (Directory.Exists(PngPath) == false)
            {
                Directory.CreateDirectory(PngPath);
            }

            PngPath += file_name + ".png";  // 需要修改，更新未原来地址

            return PngPath;
        }
        // 打印PDF
        void printPdf()
        {
            WriteInt(st40_print, 1);
            OpenFileDialog openFileDialog = new OpenFileDialog();
            //openFileDialog.InitialDirectory = "c:\\";//注意这里写路径时要用c:\\而不是c:\
            openFileDialog.Filter = "PDF文件|*.pdf";
            openFileDialog.RestoreDirectory = true;
            openFileDialog.FilterIndex = 1;

            DialogResult result = openFileDialog.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                string PDFPath = openFileDialog.FileName;
                string fileName = Path.GetFileNameWithoutExtension(PDFPath);
                string PngPath = getPath(fileName);
                PdfToImage(PDFPath, PngPath);
                NetForm.PrintImage(PngPath);
                Task.Run(() =>
                {
                    Task.Delay(1000).Wait();

                    if (print_status == 4)
                    {
                        WriteBool(st40_printing, true);
                        while (true)
                        {
                            if (print_status == 0)
                            {
                                WriteBool(st40_printReady, true);
                                ShowMsg("打印完成，马上退出！");
                                break;
                            }
                            Task.Delay(500).Wait();
                        }

                        ShowMsg("等待就绪");
                    }


                });


            }
        }
        // PDF转图片
        public void PdfToImage(string pdfPath, string outputImagePath, int dpi = 300)
        {
            try
            {
                using (var document = PdfDocument.Load(pdfPath))
                {
                    // 获取第一页
                    var page = document.Render(0, 4000, 2800, dpi, dpi, PdfRenderFlags.Annotations);

                    // 将页面渲染为图片并保存
                    page.Save(outputImagePath, ImageFormat.Png);
                }
                ShowMsg("PDF 转换为图片成功！");
            }
            catch (Exception ex)
            {
                ShowMsg($"转换失败：{ex.Message}");
            }
        }
        void printFileExist(string file_name, string pdf_name)
        {
            Thread.Sleep(2000);
            WriteBool(st40_isExist, true);
            writeString(st40_printFile, $"no file:{pdf_name}.pdf");
            ShowMsg("打印文件不存在，请更新");
            while (true)
            {
                bool a = ReadBool(st40_reprint);
                if (ReadBool(st40_reprint))
                {
                    Thread.Sleep(200);
                    WriteFalse(st40_reprint);
                    if (!File.Exists(file_name))
                    {
                        printFileExist(file_name, pdf_name);

                    }
                    return;
                }
                Thread.Sleep(1000);
            }
        }
        // 文件移动
        void move_file(string old_path, string new_path)
        {
            try
            {
                // 确保目标文件夹存在
                string newfolder = Path.GetDirectoryName(new_path);
                if (!Directory.Exists(newfolder))
                {
                    Directory.CreateDirectory(newfolder);
                }

                // 移动文件（剪切）
                File.Copy(old_path, new_path);
                Console.WriteLine("文件已成功剪切到目标文件夹！");
            }
            catch (IOException ex)
            {
                Console.WriteLine($"发生错误：{ex.Message}");
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine($"权限不足：{ex.Message}");
            }
        }
        #endregion
        #region 流程监控
        void st10_func()
        {
            ShowMsg("开始检测流程");
            while (true)
            {
                if (ReadBool(st10_request))
                {
                    Thread.Sleep(500);
                    string barCode_str = ReadNumberString(st10_barCode); // 读取条码
                    BarCode bc = splicBar(barCode_str); // 解析条码
                    XY_part part_data = sql_func.SelectPNumber(bc.零件号);//查询零件号是否需要缠膜
                    if(part_data == null)
                    {
                        ShowMsg($"未查询到零件号{bc.零件号}");
                        return;
                    }
                    WriteFalse(st10_request); // 写入False
                    ShowMsg($"ST10读取条码内容为：{barCode_str}");
                    int Count = sql_func.getSU(bc.SU号);
                    if (Count == 0)
                    {
                        WriteInt(st10_haveSuNum, 2); // 没有SU号
                        ShowMsg("没有查到相关项目号");// 
                        writeString(st10_noSuStr, "SuNumber not exist");
                        Task.Run(() => st10_func());// 重新开始
                        ShowMsg("没有查到相关项目号,重新开启St10函数");// 
                        return;
                    }
                    else
                    {
                        WriteInt(st10_haveSuNum, 1); // 有SU号，继续
                    }
                    bool st10_status = sql_func.Update10(bc.SU号, XY_task.WorkState.完成); // 更新ST10数据库
                    ShowMsg("ST10 完成");
                    Task.Run(() => st20_func()); // 启动流程2
                    return;
                }
            }

        }
        void st20_func()
        {
            ShowMsg("进入ST20流程");
            while (true)
            {

                if (ReadBool(st20_request))
                {
                    Task.Run(() => st10_func()); // 当货物到达ST20后创建新的线程
                    Thread.Sleep(500);
                    WriteFalse(st20_request);  // 关闭请求2
                    ShowMsg("ST20进入");
                    string barCode = ReadNumberString(st20_barCode); // 读码
                    BarCode bc = splicBar(barCode); // 读码
                    // 更新ST20流程，重置ST10流程
                    // 更新数据库
                    bool bl = sql_func.Update20(bc.SU号, XY_task.WorkState.完成);
                    XY_part part_data = sql_func.SelectPNumber(bc.零件号);//查询零件号是否需要缠膜
                    WriteInt(st20_wrap, Convert.ToInt16(part_data.PWrapping)); //直接从当前进度读取是否需要缠膜
                    ShowMsg("缠膜完成");
                    Task.Run(() => st30_func()); // 启动ST30函数，结束ST20函数
                    return;
                }
            }
        }
        void st30_func()
        {
            ShowMsg("进入ST30流程");
            while (true)
            {
                if (ReadBool(st30_request))
                {
                    Thread.Sleep(500);
                    WriteFalse(st30_request); // 关闭信号
                    ShowMsg("ST30进入");
                    string barCode = ReadNumberString(st30_barCode); // 读码
                    BarCode bc = splicBar(barCode); // 读码
                    // 更新ST30流程，重置ST20流程
                    XY_part Part20 = sql_func.SelectPNumber(bc.零件号);//查询零件号是否需要缠膜
                    ShowMsg("ST20 发送");
                    bool bl = sql_func.Update30(bc.SU号, XY_task.WorkState.完成); // 更新新数据库
                    ShowMsg("开始缠膜");  // 缠膜直接由ST20发送
                    Task.Run(() => st40_func()); // 启动ST40
                    return;
                }
            }
        }

        

        private void label3_Click(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            // 双击托盘图标恢复窗口
            this.Show(); // 显示窗口
            this.WindowState = FormWindowState.Normal; // 恢复正常状态
            this.ShowInTaskbar = true; // 显示任务栏图标
        }

        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            // 检测窗口是否最小化
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide(); // 隐藏窗口
                notifyIcon1.Visible = true; // 显示托盘图标
            }
        }

        void st40_func()
        {
            ShowMsg("进入ST40流程");
            while (true)
            {
                if (ReadBool(st40_request))
                {
                    Thread.Sleep(500);
                    WriteFalse(st40_request);

                    string barCode = ReadNumberString(st40_barCode); // 读码

                    BarCode bc = splicBar(barCode); // 读码
                    // 更新ST40流程，重置ST30流程
                    bool bl = sql_func.Update40(bc.SU号, XY_task.WorkState.进入);// 更新数据库
                    XY_part part_data = sql_func.SelectPNumber(bc.零件号);//查询零件号是否需要缠膜
                    WriteInt(st40_print, Convert.ToInt16(part_data.PPaying)); // 打印
                    XY_taskdetail Td = sql_func.SelectStorage_unit_number(bc.SU号);
                    if (part_data.PPaying == "1")
                    {
                        
                        // Td.PrintTask为dn号+item号的路径
                        string PDFPath = PrintPath + Td.PrintTask + ".pdf"; // pdf路径
                        string newPDFPath = newPrintPath + Td.PrintTask + ".pdf";

                        ShowMsg($"打印文件为：{Td.PrintTask}.pdf");
                        printFileLabel.Text = $"打印文件：{Td.PrintTask}.pdf"; // 将打印的文件名称更新在界面上

                        if (!File.Exists(PDFPath))
                        {
                            printFileExist(PDFPath, Td.PrintTask);
                        }
                        move_file(PDFPath, newPDFPath); // 将旧文件移动到新文件夹
                        newPrintFile = newPDFPath; // 赋值给全局变量

                        // 更新st40进度为C
                        string PngPath = getPath(Td.PrintTask);// 获取png路径

                        PdfToImage(newPDFPath, PngPath);// 转换图片并且保存到本地
                        NetForm.PrintImage(PngPath); //
                        while (true)
                        {
                            Thread.Sleep(1000);
                            if (print_status == 4)
                            {
                                WriteBool(st40_printing, true);
                                while (true)
                                {
                                    if (print_status == 0)
                                    {
                                        WriteBool(st40_printReady, true);
                                        ShowMsg("打印完成，马上退出！");
                                        printFileLabel.Text = "打印文件";
                                        break;
                                    }
                                    Task.Delay(500).Wait();
                                }
                                break;
                            }
                        }
                        while (true)
                        {
                            if (ReadBool(st40_request2))
                            {
                                //托盘标签码 HU号
                                string hu_num = ReadNumberString("DB200.DBB712").Replace("\0", "");
                                //保存HU
                                bool b = sql_func.UpdateHU(bc.SU号, hu_num);

                                sql_func.Update42(bc.SU号, hu_num, XY_task.WorkState.完成, Td.PrintTask);


                                // 更新数据库完成
                                Thread.Sleep(500);
                                WriteFalse(st40_request2);
                                ShowMsg("ST40结束");
                                break;
                            }
                        }
                    }                    
                    ShowMsg("ST40结束");
                    Task.Run(() => st50_func());
                    return;
                }
            }
        }
        // ST50函数
        void st50_func()
        {
            ShowMsg("开启ST50流程");
            while (true)
            {
                if (ReadBool(st50_request))
                {
                    ShowMsg("ST50 进入");
                    Thread.Sleep(500);
                    WriteFalse(st50_request); // 复位ST50
                    ShowMsg("更新ST50进度。");
                    // 更新ST50进度，重置ST40进度
                    track_intflag++;
                    string barCode = ReadNumberString(st50_barCode); // 读码
                    BarCode bc = splicBar(barCode); // 读码
                    bool bl = sql_func.Update50(bc.SU号, XY_task.WorkState.完成);
                    Thread.Sleep(2000);   //等待2秒
                    ShowMsg("ST50结束");
                    return;
                }
            }
        }
        // ST60函数
        void st60_func()
        {
            ShowMsg("进入ST60流程");
            while (true)
            {
                if (ReadBool(st60_request))
                {
                    track_intflag++;// 提升机判断
                    if(track_intflag == 3)
                    {
                        track_intflag = 4;

                    }
                    WriteFalse(st60_request);
                    ShowMsg("进入ST60");
                    string barCode = ReadNumberString(st50_barCode); // 读码
                    BarCode bc = splicBar(barCode); // 读码
                    bool IsStacking = ReadBool(st60_isStock);// 判断升降机是否有货
                    sql_func.Update60(bc.SU号, XY_task.WorkState.进入);
                    if (IsStacking)
                    {
                        // 更新ST60，重置ST50
                        track_intflag++;
                        ShowMsg("第二托线程结束");
                        return;  // 关闭线程
                    }
                    else
                    {
                        sql_func.Update60(stationRecords[5].SU_num_down, XY_task.WorkState.进入);
                        XY_part part_data = sql_func.SelectPNumber(bc.零件号);//查询零件号是否需要缠膜

                        if (part_data.PStacking == "1") // 判断堆叠
                        {
                            // 开始堆叠
                            realTime = waitRaiseTime; // 获取等待时间
                        
                            while (realTime > 0)
                            {
                                if (track_intflag == 3) // 等待ST50进入并且更新进度
                                {
                                    if (stationRecords[4].Part_num == stationRecords[5].Part_num)
                                    {
                                        WriteInt(st60_Stack, 1);//提升机开始提升
                                        ShowMsg("到位！开始提升");
                                        while (true)  // 等待第二托进入
                                        {
                                            if (track_intflag > 3) // 第二托进入，track_flag = false
                                            {
                                              
                                                Thread.Sleep(500);
                                                ShowMsg("第二托进入！准备堆叠");
                                                WriteInt(st60_Stack, 1);
                                                break;
                                            }
                                            Thread.Sleep(500);
                                        }
                                        while (true)  // 等待请求2
                                        {
                                            if (ReadBool(st60_request2)) // 堆叠完成的判断
                                            {
                                                Thread.Sleep(500);
                                                ShowMsg("堆叠完成");
                                                WriteFalse(st60_request2);
                                                track_intflag = 0;
                                                Task.Run(() => st70_func()); // 开启ST50流程
                                                return;
                                            }
                                            Thread.Sleep(500);
                                        }
                                    }
                                    else
                                    {
                                        realTime = 0;// 结束当前循环
                                    }
                                }
                                
                                Thread.Sleep(1000); // 等待
                                realTime -= 1;
                            }
                            
                            if (realTime <= 0)
                            {
                                WriteInt(st60_Stack, 2); // 不堆叠

                                while (true)  // 等待请求2
                                {
                                    if (ReadBool(st60_request2))
                                    {
                                        Thread.Sleep(500);
                                        WriteFalse(st60_request2);
                                        break;
                                    }
                                    Thread.Sleep(200);
                                }
                            }
                            Task.Run(() => st70_func());
                            return;
                        }
                        else
                        {
                            WriteInt(st60_Stack, 2); // 不堆叠

                            ShowMsg("不堆叠");
                            while (true)
                            {
                                if (ReadBool(st60_request2))
                                {
                                    Thread.Sleep(500);
                                    sql_func.Update60(bc.SU号, XY_task.WorkState.完成);
                                    WriteFalse(st60_request2);
                                    ShowMsg("ST60请求2复位");
                                    break;
                                }
                            }
                            track_intflag = 0;
                            Task.Run(() => st70_func());
                            return;
                        }

                    }
                }
            }
        }

        // ST70函数
        void st70_func()
        {
            ShowMsg("进入ST70流程");
            while (true)
            {
                if (ReadBool(st70_request))
                {
                    Thread.Sleep(500);
                    WriteFalse(st70_request);

                    ShowMsg("ST70结束等更新");
                    if (stationRecords[6].HU_num_up != "待更新")
                    {
                        sql_func.Update70(stationRecords[6].SU_num_up, XY_task.WorkState.进行中);// 更新上托信息
                    }
                    sql_func.Update70(stationRecords[6].SU_num_down, XY_task.WorkState.进行中);// 更新下托信息
                    //MQTT回读
                    MQTTPush(stationRecords[6].SU_num_down);
                    WriteInt(st70_Push, Convert.ToInt16(stationRecords[6].Push));
                    while (true)
                    {
                        if (ReadBool(st70_leave))
                        {
                            Thread.Sleep(500);
                            XY_part part_data = sql_func.SelectPNumber(stationRecords[6].Part_num);
                            ShowMsg($"part_data.PDirection:{part_data.PDirection}");
                            
                            // 查询dn号
                            XY_taskdetail task_data = sql_func.SelectStorage_unit_number("1045019541");
                            string dn_num = task_data.dropdown_station_storage_bin;
                            if (stationRecords[6].SU_num_up.Length < 8)
                            {
                                update_agv_site(agv_position, dn_num, false); // 更新到AGV数据库
                            }
                            else
                            {
                                update_agv_site(agv_position, dn_num, true);
                            }
                            ini.WriteKey("agv_position", agv_position.ToString());
                            ShowMsg($"将会发送到:{agv_position}位置");
                            callAgv(agv_position, part_data.PDirection);
                            agv_position += 1;
                            if (agv_position == 4)
                            {
                                agv_position = 1;
                            }
                            WriteFalse(st70_leave);
                            
                            break;
                        }
                    }
                    while (true)
                    {
                        if (ReadBool(st70_leaved))
                        {
                            Thread.Sleep(500);
                            WriteFalse(st70_leaved);
                            ShowMsg("货物已拉走");
                            if (stationRecords[6].HU_num_up != "待更新")
                            {
                                sql_func.Update80(stationRecords[6].SU_num_up);// 更新上托信息
                            }
                            sql_func.Update80(stationRecords[6].SU_num_down);// 更新下托信息
                            break;
                        }
                    }
                    return;
                }
            }
        }

        #endregion
        #region 数据库相关函数
        void update_agv_site(int agv_pos, string dm_code,bool is_track)

        {
            string sql;
            int count;
            if (is_track) // 堆叠填写数据
            {
                sql = $"UPDATE XY_ParkingLot SET ID = {agv_pos}, [TO] = 'null', DN = '{dm_code}', LJ = '{stationRecords[6].Part_num}', HU = '{stationRecords[6].HU_num_up}', SU = '{stationRecords[6].SU_num_up}', OID = 0 WHERE TID = {agv_pos * 2 - 1};";
                count = DapperHelper<XY_ParkingLot>.Execute(sql);
            }
            else // 不堆叠数据填写空
            {
                sql = $"UPDATE XY_ParkingLot SET ID = {agv_pos}, [TO] = 'null', DN = 'null', LJ = 'null', HU = 'null', SU = 'null', OID = 0 WHERE TID = {agv_pos * 2 - 1};";
                count = DapperHelper<XY_ParkingLot>.Execute(sql);
                ShowMsg(sql);
            }

            sql = $"UPDATE XY_ParkingLot SET ID = {agv_pos}, [TO] = 'null', DN = '{dm_code}', LJ = '{stationRecords[6].Part_num}', HU = '{stationRecords[6].HU_num_down}', SU = '{stationRecords[6].SU_num_down}', OID = 1 WHERE TID = {agv_pos * 2};";
            count = DapperHelper<XY_ParkingLot>.Execute(sql);
        }

        void update_agv_data(int agv_pos, string order_id,string dn_code,string part_name,string hu,string su,int up_down)

        {
            // int =  0上，int = 1下托
            string sql = $"UPDATE XY_ParkingLot SET ID = {agv_pos}, [TO] = '{order_id}', DN = '{dn_code}', LJ = '{part_name}', HU = '{hu}', SU = '{su}', OID = {up_down} WHERE TID = {agv_pos * 2 -1 + up_down};";
            int count = DapperHelper<XY_ParkingLot>.Execute(sql);
            if (count > 0)
            {
                ShowMsg("更新成功");
            }
           
        }
        void audio_play(int station)
        {
            // POST 请求的数据
            var data = new
            {
                text = $"{station}号卸料点来货请注意安全。",
                vcn = "xiaoyan",
                speed = 40,
                volume = 100,
                rdn = "0",
                rcn = "0",
                reg = 0,
                sync = false,
                queue = false,
                loop = new
                {
                    duration = 25,
                    times = 5,
                    gap = 2
                },
                prompt = false
            };

            // 将数据序列化为 JSON
            string jsonData = JsonConvert.SerializeObject(data);

            // 设置 HTTP 请求头并发送 POST 请求
            using (HttpClient client = new HttpClient())
            {
                var content = new StringContent(jsonData, Encoding.UTF8, "application/json");

                // 发送同步 POST 请求
                HttpResponseMessage response = client.PostAsync(speaker_url, content).Result;

                // 读取响应
                string responseBody = response.ReasonPhrase;
                ShowMsg($"{station}号语音播报,成功");
            }
        }






        #endregion
        #region 进度更新


        #endregion
    }
    // 条码信息
    public class BarCode
    {
        public string 零件号 { get; set; }
        public string 工厂代码 { get; set; }
        public int 数量 { get; set; }
        public string SU号 { get; set; }
        public string 入库日期 { get; set; }
    }



    public class StationRecord
    {
        public string SU_num_up {  get; set; }  // SU号
        public string HU_num_up { get; set; } // HU号
        public string is_warp { get; set; } // 是否缠膜
        public string is_print { get; set; } // 是否打印
        public string is_stack {  get; set; }// 是否堆叠
        public string Part_num {  get; set; }// 是否堆叠
        public string SU_num_down { get; set; }  // SU号
        public string HU_num_down { get; set; } // HU号
        public string Station_position { get; set; } // 当前工位进度
        public string Push { get; set; } // 是否侧推
    }


}
